package electionCtrl;

import javax.xml.stream.XMLStreamException;

import xml.MockVotingXMLReader;
import xml.MockVotingXMLWriter;

/**
 * Creates a candidate to be processed.
 * @author Rick Thompson
 * @author Isaac Rudich
 * @author David Nicholson
 * @author Nathan Ong
 */
public final class Candidate implements Comparable<Candidate>
{
	/**
	 * The name of the candidate.
	 */
	public final String name;

	/**
	 * The Seats in which the Candidates can run for.
	 * @author Nathan Ong
	 */
	//ALL POSSIBLE SEATS MUST BE ADDED TO THIS ENUM
	public enum Seat{
		/**
		 * The candidate is running for the position of Governor.
		 */
		GOVERNOR,

//		/**
//		 * The candidate is running for the position of Lieutenant Governor.
//		 */
//		LT_GOVERNOR,

		/**
		 * The candidate is running for the position of United States Senate.
		 */
		US_SENATE,

		/**
		 * The candidate is running for the position of United States House of Representatives.
		 */
		US_HOUSE,

		/**
		 * The candidate is running for the position of Pennsylvania State Senate.
		 */
		PENN_SENATE,

		/**
		 * The candidate is running for the position of Pennsylvania State House of Representatives.
		 */
		PENN_HOUSE;
		
		public String toString()
		{
			String str = super.toString();
			return str.substring(0,1) + str.substring(1).toLowerCase().replaceAll("_", " ");
		}
	};

	/**
	 * The Seat in which the Candidate is running for.
	 */
	public final Seat seat;

	/**
	 * The party that the Candidate is running for in the form of a String.
	 */
	public final String party;

	/**
	 * The constructor of a candidate.  Requires a name, a seat (specified by the Seat enum), and a party.
	 * @param name Takes the name in the form of a String.
	 * @param seat Takes the seat the Candidate is running for in the form of a Seat.
	 * @param party Takes in the party name in the form of a String.
	 */
	public Candidate(String name, Seat seat, String party)
	{
		if(name == null || seat == null || party == null)
		{
			throw new IllegalArgumentException("The parameters cannot be null");
		}

		this.seat = seat;
		this.name = name;
		this.party = party;
	}

	public Candidate(MockVotingXMLReader reader) throws XMLStreamException  {
		String next = reader.next();
		String nameIn = "";
		String seatIn = ""; 
		String partyIn = "";
	
		while (!next.equals("</Candidate>") && !next.equals("</Vote>")) {//to optimize laziness
			next = reader.next();
			if (next.equals("<Name>")) {
				next = reader.next();
				while (!next.equals("</Name>")) {
					nameIn += next;
					next = reader.next();
				}
			}

			if (next.equals("<Seat>")) {
				next = reader.next();
				while (!next.equals("</Seat>")) {
					seatIn += next;
					next = reader.next();
				}
			}

			if (next.equals("<Party>")) {
				next = reader.next();
				while (!next.equals("</Party>")) {
					partyIn += next;
					next = reader.next();
				}
			}
		}

		Seat seat = null;
		
		for(Seat check : Seat.values())
		{
			if(seatIn.toString().toUpperCase().replace(' ','_').equals(check.toString().toUpperCase().replace(' ','_')))
			{
				seat = check;
				break;
			}
		}
		
		if(seat == null)
		{
			throw new IllegalArgumentException("Seat not found");
		}

		this.name = nameIn;
		this.seat = seat;
		this.party = partyIn;
		
	}


	public void writeToXML(MockVotingXMLWriter writer) throws XMLStreamException {
		writer.writeStartElement("Candidate");
		writer.pushHierarchy();
		writer.writeNewline();
		writer.writeTag("Name",name);
		writer.writeTag("Seat",seat.toString());
		writer.writeTag("Party",party);
		writer.pullHierarchy();
		writer.writeEndElement();
	}

	/**
	 * Returns the name, seat, and party of the Candidate.
	 */
	public String toString()
	{
		return name+", "+seat+", "+party;
	}

	public boolean equals(Object o)
	{
		if(!(o instanceof Candidate))
		{
			return false;
		}
		Candidate c = (Candidate)o;
		return this.seat == c.seat && this.name.equals(c.name) && this.party.equals(c.party);
	}

	/**
	 * finds seat number *gasp* :O
	 * @param candidates the candidate array being worked with
	 * @return the number of seats
	 */
	public static int numOfSeatsPresent(Candidate[] candidates)
	{
		boolean[] seatsIncluded = new boolean[Seat.values().length];
		for(Candidate c : candidates)
		{
			seatsIncluded[c.seat.ordinal()] = true;
		}
		int seats = 0;
		for(boolean seatIsIncluded : seatsIncluded)
		{
			seats += seatIsIncluded ? 1 : 0;
		}
		return seats;
	}

	public int compareTo(Candidate o)
	{
		return this.seat.compareTo(o.seat);
	}
}